package com.mall.product.server.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.mall.common.core.domain.Result;
import com.mall.common.log.annotation.Log;
import com.mall.common.redis.service.RedisService;
import com.mall.product.common.domain.PmsShop;
import com.mall.product.common.domain.PmsSkuInfo;
import com.mall.product.server.mapper.PmsSkuInfoMapper;
import com.mall.product.server.service.IPmsSkuInfoService;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class PmsSkuInfoServiceImpl implements IPmsSkuInfoService {

    @Autowired
    private PmsSkuInfoMapper pmsSkuInfoMapper;
    @Autowired
    private RedisService redisService;




    @Override
    public List<PmsSkuInfo> selectPmsSkuInfoList(PmsSkuInfo pmsSkuInfo) {
        return pmsSkuInfoMapper.selectPmsSkuInfoList(pmsSkuInfo);
    }

    @Override
    public PmsSkuInfo selectPmsSkuInfoBySkuId(Long id) {
        return pmsSkuInfoMapper.selectPmsSkuInfoBySkuId(id);
    }

    @Override
    public PmsSkuInfo getInfo(Long skuId) {
        return pmsSkuInfoMapper.selectPmsSkuInfoBySkuId(skuId);
    }

    @Override
    public Result<PmsShop> findShopByShopId(Long shopId) {
        return Result.success(pmsSkuInfoMapper.findShopByShopId(shopId));
    }

    @Override
    public List<PmsSkuInfo> findLowInventoryNumSkuList(Long shopId) {
        return pmsSkuInfoMapper.findLowInventoryNumSkuList(shopId);
    }

    /**
     * 项目启动库存预热3天有效期
     */
    @Override
    public void init() {
        //查询出所有的skuId和库存
        List<PmsSkuInfo> pmsSkuInfos = pmsSkuInfoMapper.selectPmsSkuInfoList(new PmsSkuInfo());
        //使用stream流进行遍历插入redis中
        pmsSkuInfos.stream().forEach(pmsSkuInfo -> {
            //随机生成一个过期时间12小时至36小时之间
            redisService.setCacheObject("SkuInventoryNum:"+pmsSkuInfo.getSkuId(),
                    pmsSkuInfo.getInventoryNum(),(long) (Math.random()*24+12), TimeUnit.HOURS);
        });

        pmsSkuInfos.stream().forEach(pmsSkuInfo -> {
            //随机生成一个过期时间12小时至36小时之间
            redisService.setCacheObject("HotSku:"+pmsSkuInfo.getSkuId(),
                    pmsSkuInfo.getPrice(),
                    (long) (Math.random()*24+12), TimeUnit.HOURS);
        });

    }

    /**
     * 获取热销商品库存数据，使用分布式锁进行并发控制
     * @param key
     * @return
     */
    public Integer getHotDataWithLock(String key) {
        // 尝试从缓存获取数据
        String cacheData = redisService.getCacheObject("SkuInventoryNum:"+key);
        if (cacheData != null) {
            return Integer.valueOf(cacheData);
        }
        //如果redis中没有数据，则从数据库中获取数据并设置缓存，同时使用分布式锁控制并发
        String lockKey = "lock:" + key;
        String lockValue = UUID.randomUUID().toString();
        Boolean lockResult = redisService.redisTemplate.opsForValue().setIfAbsent("lock:" + key, "locked", 3, TimeUnit.SECONDS);
        if (Boolean.TRUE.equals(lockResult)) {
            try {
                // 再次检查缓存，防止重复设置
                cacheData = redisService.getCacheObject("SkuInventoryNum:"+key);
                if (cacheData == null) {
                    // 模拟从数据库加载数据的过程
                    PmsSkuInfo pmsSkuInfo = pmsSkuInfoMapper.selectPmsSkuInfoBySkuId(Long.valueOf(key));
                    // 更新缓存
                    redisService.setCacheObject("SkuInventoryNum:"+key, pmsSkuInfo.getInventoryNum(),(long) (Math.random()*24+12), TimeUnit.MINUTES);
                }
            } finally {
                // 释放锁
                redisService.redisTemplate.delete("lock:" + key);
                return Integer.valueOf(redisService.getCacheObject("SkuInventoryNum:"+key));
            }
        }else {
            // 如果获取锁失败，可以进行短暂的休眠后重试
            try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); }
            return getHotDataWithLock(key);
        }
    }





}
